package com.kk.xhr.admin.biz.impl;

import com.kk.xhr.admin.biz.IDepartmentBizService;
import com.kk.xhr.admin.controller.request.DepartmentAddRequest;
import com.kk.xhr.admin.controller.request.DepartmentModifyRequest;
import com.kk.xhr.admin.controller.vo.DepartmentTreeVO;
import com.kk.xhr.admin.controller.vo.TeamVO;
import com.kk.xhr.admin.controller.vo.UserVO;
import com.kk.xhr.common.ErrorCodeEnum;
import com.kk.xhr.common.exception.BusinessException;
import com.kk.xhr.common.pojo.BinaryEnum;
import com.kk.xhr.model.dto.DepartmentDTO;
import com.kk.xhr.model.dto.DepartmentTreeDTO;
import com.kk.xhr.model.dto.NotificationDTO;
import com.kk.xhr.model.dto.UserDTO;
import com.kk.xhr.model.entity.Role;
import com.kk.xhr.model.service.IDepartmentService;
import com.kk.xhr.model.service.ILevelService;
import com.kk.xhr.model.service.INotificationService;
import com.kk.xhr.model.service.IPositionService;
import com.kk.xhr.model.service.IRoleService;
import com.kk.xhr.model.service.IUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 部门biz服务接口实现
 *
 * @author kkmystery
 * @version 1.0 2021/3/5
 * @since 1.0.0
 */
@Service
@RequiredArgsConstructor
public class DepartmentBizServiceImpl implements IDepartmentBizService {
    private final IDepartmentService departmentService;
    private final IUserService userService;
    private final IPositionService positionService;
    private final ILevelService levelService;
    private final IRoleService roleService;
    private final INotificationService notificationService;

    @Override
    public DepartmentTreeVO query(Long id) {
        DepartmentTreeDTO dto = departmentService.query(id);
        if (null == dto) {
            throw new BusinessException(ErrorCodeEnum.DEPARTMENT_NOT_EXIST);
        }
        return generateVO(dto);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public TeamVO queryTeam(Long userId) {
        UserDTO user = userService.queryById(userId)
            .orElseThrow(() -> new BusinessException(ErrorCodeEnum.USER_NOT_EXIST));
        DepartmentDTO department = departmentService.queryById(user.getDepartmentId())
            .orElseThrow(() -> new BusinessException(ErrorCodeEnum.DEPARTMENT_NOT_EXIST));
        List<UserDTO> list = userService.queryByDepartmentId(user.getDepartmentId());
        return TeamVO.builder()
            .leader(UserVO.builder()
                .name(userService.queryName(department.getUserId()))
                .department(department.getName())
                .build())
            .member(list.stream()
                .map(dto -> this.generateUserVO(dto, department.getName()))
                .collect(Collectors.toList()))
            .build();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(DepartmentAddRequest request) {
        departmentService.modify(DepartmentDTO.builder()
            .id(request.getParentId())
            .parent(BinaryEnum.FALSE.toBoolean())
            .build());
        long id = departmentService.add(DepartmentDTO.builder()
            .userId(request.getLeaderId())
            .name(request.getName())
            .parentId(request.getParentId())
            .path(request.getPath())
            .parent(false)
            .build());
        userService.modify(UserDTO.builder()
            .id(request.getLeaderId())
            .departmentId(id)
            .build());
        // 设置角色为主管
        Set<String> roles = roleService.queryRolesByUserId(request.getLeaderId())
            .stream().map(Role::getName).collect(Collectors.toSet());
        if (roles.contains("leader")) {
            roleService.addUserRole(request.getLeaderId(), Collections.singletonList(2L));
        }
        notificationService.add(NotificationDTO.builder()
            .userId(request.getLeaderId())
            .message("您已成为新的部门负责人！请前往我的部门查看")
            .build());
    }

    @Override
    public void modify(Long id, DepartmentModifyRequest request) {
        DepartmentDTO department = departmentService.queryById(id)
            .orElseThrow(() -> new BusinessException(ErrorCodeEnum.DEPARTMENT_NOT_EXIST));
        departmentService.modify(DepartmentDTO.builder()
            .id(id)
            .userId(request.getLeaderId())
            .name(request.getName())
            .parentId(request.getParentId())
            .path(request.getPath())
            .build());
        if (null != request.getLeaderId()) {
            userService.modify(UserDTO.builder()
                .id(request.getLeaderId())
                .departmentId(id)
                .build());
        }
        if (0 == departmentService.queryByUserId(department.getUserId()).size()) {
            // 若无负责部门，则将原来的负责人角色删除
            roleService.deleteLeaderRole(department.getUserId());
        }
        // 查询新负责人是否为leader角色，若不为leader则晋升为leader
        Set<String> roles = roleService.queryRolesByUserId(request.getLeaderId())
            .stream().map(Role::getName).collect(Collectors.toSet());
        if (roles.contains("leader")) {
            roleService.addUserRole(request.getLeaderId(), Collections.singletonList(2L));
        }
        notificationService.add(NotificationDTO.builder()
            .userId(request.getLeaderId())
            .message("您已成为新的部门负责人！请前往我的部门查看")
            .build());
    }

    @Override
    public boolean modifyStatus(Long id, BinaryEnum status) {
        if (0 < userService.queryByDepartmentId(id).size()) {
            throw new BusinessException(ErrorCodeEnum.DEPARTMENT_DELETE_FAIL);
        }
        // 递归
        DepartmentTreeDTO tree = departmentService.query(id);
        Set<Long> ids = new HashSet<>();
        ids.add(id);
        getIds(tree, ids);
        return departmentService.modifyStatus(ids, status);
    }

    private void getIds(DepartmentTreeDTO tree, Set<Long> ids) {
        ids.add(tree.getId());
        for (DepartmentTreeDTO child : tree.getChildren()) {
            getIds(departmentService.query(child.getId()), ids);
        }
    }

    @Override
    public boolean checkLeader(Long userId) {
        return departmentService.checkByUserId(userId);
    }

    /**
     * 递归生成部门
     *
     * @param dto DepartmentTreeDTO
     * @return DepartmentTreeVO
     */
    private DepartmentTreeVO generateVO(DepartmentTreeDTO dto) {
        List<DepartmentTreeVO> children = new ArrayList<>();
        DepartmentTreeVO vo = DepartmentTreeVO.builder()
            .id(dto.getId())
            .leader(userService.queryName(dto.getUserId()))
            .leaderId(dto.getUserId())
            .name(dto.getName())
            .parentId(dto.getParentId())
            .parent(dto.getParent())
            .path(dto.getPath())
            .build();
        for (DepartmentTreeDTO child : dto.getChildren()) {
            children.add(generateVO(child));
        }
        vo.setChildren(children.isEmpty() ? null : children);
        return vo;
    }

    /**
     * UserVO 生成器
     *
     * @param dto        UserDTO
     * @param department 部门名称
     * @return UserVO
     */
    private UserVO generateUserVO(UserDTO dto, String department) {
        return UserVO.builder()
            .id(dto.getId())
            .workId(dto.getWorkId())
            .workAge(dto.getWorkAge())
            .name(dto.getName())
            .telephone(dto.getTelephone())
            .department(department)
            .phone(dto.getPhone())
            .email(dto.getEmail())
            .position(positionService.queryById(dto.getPositionId()).get().getName())
            .level(levelService.queryById(dto.getLevelId()).get().getLevel())
            .build();
    }
}
